package net.linlan.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;

/**
 * createtime: 2019/8/13 16:03
 */
@Configuration
@ConditionalOnProperty(value = "spring.redis.cluster.nodes")
@ConditionalOnClass({JedisCluster.class,JedisPoolConfig.class})
public class JedisConfig {
    private static final Logger logger = LoggerFactory.getLogger(JedisConfig.class);


    @Value("${spring.redis.cluster.nodes}")
    private String clusterNodes;
    @Value("${spring.redis.password}")
    private String clusterPassword;
    private static JedisPoolConfig jedisPoolConfig;

    /**
     * redis address, like "{ip}"、"{ip}:{port}"、"{redis/rediss}://sso:{password}@{ip}:{port:6379}/{db}"；Multiple "," separated
     */
//    private static String address;
//    private static ShardedJedisPool shardedJedisPool;
    /**
     *maxIdle实际上才是业务需要的最大连接数，maxTotal是为了给出余量，所以maxIdle不要设置过小，否则会有new Jedis(新连接)开销，而minIdle是为了控制空闲资源监测。
     *连接池的最佳性能是maxTotal = maxIdle ,这样就避免连接池伸缩带来的性能干扰。但是如果并发量不大或者maxTotal设置过高，会导致不必要的连接资源浪费。
     *可以根据实际总OPS和调用redis客户端的规模整体评估每个节点所使用的连接池。
     */
    static {
        jedisPoolConfig = new JedisPoolConfig();
        // 一、资源设置和使用
        // 资源池中最大连接数 默认值8
        jedisPoolConfig.setMaxTotal(200);
        // 资源池允许最大空闲的连接数 默认值8
        jedisPoolConfig.setMaxIdle(520);
        // 资源池确保最少空闲的连接数 默认值0
        jedisPoolConfig.setMinIdle(10);
        // 当资源池用尽后，调用者是否要等待 默认值true 只有当为true时，maxWaitMillis才会生效 建议使用默认值
//        jedisPoolConfig.setBlockWhenExhausted(true);
        // 当资源池连接用尽后，调用者的最大等待时间(单位为毫秒) 默认值-1：表示永不超时 不建议使用默认值
        jedisPoolConfig.setMaxWaitMillis(3000);
        // 向资源池借用连接时是否做连接有效性检测(ping)，无效连接会被移除 默认值false 业务量很大时候建议设置为false(多一次ping的开销)
        jedisPoolConfig.setTestOnBorrow(true);
        // 向资源池归还连接时是否做连接有效性检测(ping)，无效连接会被移除 默认值false 业务量很大时候建议设置为false(多一次ping的开销)
        jedisPoolConfig.setTestOnReturn(false);
        // 是否开启jmx监控，可用于监控 默认值true 建议开启，但应用本身也要开启
//        jedisPoolConfig.setJmxEnabled(true);

        // 二、空闲资源监测
        // 是否开启空闲资源监测 默认值false 建议true
        jedisPoolConfig.setTestWhileIdle(true);
        // 空闲资源的检测周期(单位为毫秒) 默认值-1：不检测 建议设置，周期自行选择，可以使用30000
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
        // 表示idle object evitor每次扫描的最多的对象数
        jedisPoolConfig.setNumTestsPerEvictionRun(10);
        // 资源池中资源最小空闲时间(单位为毫秒)，达到此值后空闲资源将被移除 默认值1000*60*30 = 30分钟 可根据自身业务决定，大部分默认值即可，也可以考虑使用下面JeidsPoolConfig中的配置
        jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);
        // 做空闲资源检测时，每次的采样数 默认值3 可根据自身应用连接数进行微调,如果设置为-1，就是对所有连接做空闲监测
        jedisPoolConfig.setNumTestsPerEvictionRun(3);

//        // JedisShardInfo List
//        List<JedisShardInfo> jedisShardInfos = new LinkedList<JedisShardInfo>();
//
//        String[] addressArr = address.split(",");
//        for (int i = 0; i < addressArr.length; i++) {
//            JedisShardInfo jedisShardInfo = new JedisShardInfo(addressArr[i]);
//            jedisShardInfos.add(jedisShardInfo);
//        }
//        shardedJedisPool = new ShardedJedisPool(jedisPoolConfig, jedisShardInfos);
//        logger.info(">>>>>>>>>>> Jedis ShardedJedisPool init success.");


    }

//    /**
//     * 单节点
//     * @return
//     */
//    @Bean
//    public JedisPool jedisPoolFactory(){
//        return new JedisPool(jedisPoolConfig, host, port, 5000);
//    }


    @Bean
    public JedisCluster jedisCluster(){
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        for (String redisAddress:clusterNodes.split(",")){
            String[] host = redisAddress.split(":",2);
            nodes.add(new HostAndPort(host[0],Integer.valueOf(host[1])));
        }
//        return new JedisCluster(nodes,10000,5000);
        if (StringUtils.hasText(clusterPassword)){
            return new JedisCluster(nodes, 10000, 5000, 1, clusterPassword, jedisPoolConfig);
        }
        return new JedisCluster(nodes, 10000, 5000, 1, jedisPoolConfig);
    }



}
